#pragma once
#include"util.hpp"
#include<list>
#include<mutex>
#include<thread>
#include"db.hpp"
template<class T>
class match_queue
{
    public:
    match_queue()
    {}
    ~match_queue()
    {}
    void Push( T& in)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        _queue.insert(_queue.end(),in);
        _cond.notify_all();
    }
    bool Pop(T& out)
    {
        if(_queue.empty()==true)
        {
            return false;
        }
        std::unique_lock<std::mutex> lock(_mutex);
        out=_queue.front();
        _queue.pop_front();
        return true;
    }
    bool Empty()
    {
        std::unique_lock<std::mutex> lock(_mutex);
        return _queue.empty();
    }
    void Wait()
    {
        std::unique_lock<std::mutex> lock(_mutex);
        _cond.wait(lock);
    }
    int Size()
    {
        std::unique_lock<std::mutex> lock(_mutex);
        return _queue.size();
    }
    void Remove(T& out)
    {
        if(_queue.empty()==true)
        {
            return;
        }
        std::unique_lock<std::mutex> lock(_mutex);
        _queue.remove(out);
    }
    private:
    std::list<T> _queue;
    std::mutex _mutex;
    std::condition_variable _cond;
};  




//匹配队列管理模块
class match_manager
{
    public:
    match_manager(online_manager* om,room_mamager* rm,user_table* ut)
    :_om(om)
    ,_rm(rm)
    ,_ut(ut)
    ,_th_Bronze(std::thread(&match_manager::_th_Bronze_entry,this))
    ,_th_Silver(std::thread(&match_manager::_th_Silver_entry,this))
    ,_th_Gold(std::thread(&match_manager::_th_Gold_entry,this))
    {

    }
    ~match_manager()
    {}
    //添加一个用户到匹配队列
    void Add_to_queue(uint64_t uid)
    {
        //判断用户是否在线：
        bool ret=_om->is_in_game_hall(uid);
        if(ret==false)
        {
            DBG_LOG("用户%ld掉线，匹配终止！！",uid);
            return;
        }
        //首先获取用户的数据信息
        Json::Value user;
        bool res=_ut->select_by_id(uid,user);
        if(res==false)
        {
            DBG_LOG("获取用户%ld信息失败，匹配终止！！",uid);
            return;
        }
        int score=user["score"].asInt();
        if(score<2000)
        {
            _q_Bronze.Push(uid);
        }
        else if(score>=2000&&score<3000)
        {
            _q_Silver.Push(uid);
        }
        else
        {
           _q_Gold.Push(uid);
        }
    }
    //从匹配队列中删除一个用户
    void Delete_from_queue(uint64_t uid)
    {   
        //首先获取用户的数据信息
        Json::Value user;
        bool res=_ut->select_by_id(uid,user);
        if(res==false)
        {
            DBG_LOG("获取用户%ld信息失败",uid);
            return;
        }
        int score=user["score"].asInt();
        if(score<2000)
        {
            _q_Bronze.Remove(uid);
        }
        else if(score>=2000&&score<3000)
        {
            _q_Silver.Remove(uid);
        }
        else
        {
           _q_Gold.Remove(uid);
        }
    }
    private:
    //三个对应的线程入口函数，完成匹配成功后的一系列操作
    void _th_Bronze_entry()
    {
        Handle_queue(_q_Bronze);
    }
    void _th_Silver_entry()
    {
        Handle_queue(_q_Silver);
    }
    void  _th_Gold_entry()
    {
        Handle_queue(_q_Gold);
    }
    void Handle_queue(match_queue<uint64_t>& queue)
    {
        while(1)
        {
            while(queue.Size()<2)
            {
                queue.Wait();
            }
            //下来说明队列中用户个数>=2
            uint64_t user1,user2;
            bool ret1=queue.Pop(user1);
            if(ret1==false)
            {
                continue;
            }
            bool ret2=queue.Pop(user1);
            if(ret2==false)
            {
                //此时已经把user1拿出来了，但是user2拿失败了
                //将user1重新添加入队列
                queue.Push(user1);
                continue;
            }
            //到这里两个用户都拿出来了，先检查两个用户是否在线
            bool ret3=_om->is_in_game_hall(user1);
            if(ret3==false)
            {
                //user1掉线了，将user2重新加入匹配队列
                queue.Push(user2);
                continue;
            }
            bool ret4=_om->is_in_game_hall(user2);
            if(ret4==false)
            {
                //user2掉线了，将user1重新加入匹配队列
                queue.Push(user1);
                continue;
            }
            //为user1和user2创建一个房间：
            room_ptr rp=_rm->creat_room(user1,user2);
            //获取两用户的连接信息：
            wsserver_t::connection_ptr user1_conn=_om->get_conn_from_hall(user1);
            wsserver_t::connection_ptr user2_conn=_om->get_conn_from_hall(user2);
            if(rp.get()==nullptr)
            {
                //创建房间失败
                //将两个用户重新加入匹配队列
                queue.Push(user1);
                queue.Push(user2);
                continue;
            }
            Json::Value mess;
            std::string body;
            mess["optype"]="match_success";
            mess["result"]=true;
            json_util::Serialize(mess,body);
            user1_conn->send(body);
            user2_conn->send(body);
        }
    }
    private:
    //三个匹配队列对应三个等级（青铜、白银、黄金）
    match_queue<uint64_t> _q_Bronze;
    match_queue<uint64_t> _q_Silver;
    match_queue<uint64_t> _q_Gold;
    //三个线程对应三个匹配队列：
    std::thread _th_Bronze; 
    std::thread _th_Silver;
    std::thread _th_Gold;
    //用户管理模块的句柄：
    online_manager* _om;
    //房间管理模块的句柄：
    room_mamager* _rm;
    //用户数据库句柄
    user_table* _ut;
};
